import pandas as pd
import os.path

from datatoolsobj.excel.multi_line_hdr_detect import ExcelMultiLineHdrDetect,HdrTypeError
from datatoolsobj.excel.excelformat import XlsxWriterFormat

import logging

logging.basicConfig(level="INFO")
mylog = logging.getLogger()


class MultiLineHdrHub():
    """
    集中处理表头列名区域跨多行的文件情况。
    """

    def __init__(self, used_sheets, multi_line_columns_conf_path, use_exist=True, conf_dir='conf'):
        """
        和ExcelHub对象构造方法相对应的参数，以便可以在原流程中，直接使用findUseSheets的结果。
        :param used_sheets: 通过findUseSheets形成的用于对多行列名处理的原始表。
        :param multi_line_columns_conf_path: 要使用的多行列名配置文件路径，如果直接指定了.xls或.xlsx的文件扩展名，则直接使用。否则对此参数字符串加.xlsx为扩展名，做为配置文件的路径。
        :param use_exist: 如果为True，则表示如果此前使用本方法生成过使用列名配置文件，则直接使用。
        :param conf_dir: 配置文件所在目录
        """
        self._used_sheets = used_sheets
        if self._used_sheets.empty:
            raise ValueError("Excel 目录数据表为空！")

        # 生成保存指定目录中所有Excel文件使用配置表信息的Excel文件
        if multi_line_columns_conf_path and (
                -1 != multi_line_columns_conf_path.find(".xls") or -1 != multi_line_columns_conf_path.find(".xlsx")):
            self._uscol_conf_path = multi_line_columns_conf_path
        elif multi_line_columns_conf_path:
            self._uscol_conf_path = multi_line_columns_conf_path + ".xlsx"
        else:
            raise FileNotFoundError("给出的Excel表配置文件路径为空！！")

        if not conf_dir:
            self._conf_dir = "conf"
        else:
            self._conf_dir = conf_dir

        # 针对涉及的每一个列，通过些表列出每个列名的信息用于进行配置
        self._multi_line_conf_df = pd.DataFrame()

        # 此处需要加入判断，如果存在配置文件，则需要根据参数确定是不直接使用
        self._conf_path = os.path.join(self._conf_dir, self._uscol_conf_path)
        if os.path.exists(self._conf_path) and use_exist:
            self.inMultiLineConfFile()
            self._new_dir = False
        else:
            # 此处为新读取文件结构
            self._multi_line_conf_df = self._walkUsedSheet()
            self._new_dir = True

    def inMultiLineConfFile(self):
        file_path = os.path.join(self._conf_dir, self._uscol_conf_path)
        if not os.path.exists(file_path):
            raise FileNotFoundError("给出的{}文件不存在！！".format(file_path))
        data = pd.read_excel(file_path, sheet_name='多列使用配置', header=1, dtype={'Sheet表名': 'str'})
        used_data = data.loc[data['是否使用'].isin(['是', 'Y', True, 'TRUE', 'True'])]
        self._multi_line_conf_df = used_data

    def outMultiLineConfFile(self):
        file_path = os.path.join(self._conf_dir, self._uscol_conf_path)
        colunmn_width = {'列名': 30, '出现次数': 20}
        with XlsxWriterFormat(file_path) as xw:
            xw.to_excel(self._multi_line_conf_df, '多列使用配置', title='多列使用配置')

    def getMultiLineConfDataFrame(self):
        return self._multi_line_conf_df

    def transfer(self):
        """通过多列使用配置文件，将多列表头转换为单列表头。"""
        sheet_same_columns = ['文件编号', '文件路径','文件名称','Sheet表名','年度', '标记',  '列名起始标识', '列名终止标识']
        detail_columns_part = ['列名', '列名行位置', '列名列位置', '是否使用', '需要细化', '细化列名']
        self._multi_used_columns_dict = {}
        self._multi_used_sheet = pd.DataFrame()
        current_used_sheet = self._multi_line_conf_df.loc[
            self._multi_line_conf_df['是否使用'].isin(['是', 'Y', True, 'TRUE', 'True'])]
        if current_used_sheet.empty:
            return None
        for same_columns, same_column_detail_paret in current_used_sheet.groupby('文件编号'):
            same_column_data = same_column_detail_paret[sheet_same_columns]
            same_column_data = same_column_data.drop_duplicates()
            if self._multi_used_sheet.empty:
                self._multi_used_sheet = same_column_data
            else:
                self._multi_used_sheet = pd.concat([self._multi_used_sheet, same_column_data], ignore_index=True)
            detail_columns_data = same_column_detail_paret[detail_columns_part]
            used_row_index = detail_columns_data['列名行位置'].max()
            min_col_index = detail_columns_data['列名列位置'].min()
            # 创建一个与列名长度一致的全None数组
            restul_columns_list = [None] * (detail_columns_data['列名列位置'].max() + 1)
            for index, row in detail_columns_data.iterrows():
                col_index = row['列名列位置'] - min_col_index
                need_detail = row['需要细化']
                if need_detail in ['是', 'Y', True, 'TRUE', 'True']:
                    # 此列名需要进行细化处理
                    if row['细化列名'] and row['细化列名'] != "":
                        if not restul_columns_list[col_index]:
                            restul_columns_list[col_index] = (row['细化列名'], row['列名行位置'], row['列名列位置'],used_row_index)
                else:
                    restul_columns_list[col_index] = (row['列名'], row['列名行位置'], row['列名列位置'],used_row_index)
                    # used_columns_list.append((row['列名'],row['列名行位置'],row['列名列位置']))
            for i in range(0, restul_columns_list.count(None)):
                restul_columns_list.remove(None)

            self._multi_used_columns_dict[same_columns] = restul_columns_list

    def getMultiUsedSheets(self):
        return self._multi_used_sheet

    def getMultiUsedColumnsDict(self):
        return self._multi_used_columns_dict

    def _findMultiLineInfo(self, file_path, sheet_name, start_flag, end_flag):
        """
        获取每个多选表头的Sheet文件中，多行表头的基本信息。
        :param file_path: 文件路径
        :param sheet_name: Sheet表名
        :param start_flag: 表头列名区域起始标志
        :param end_flag: 表头列名区域结束标志
        :return: 此表对应 '列名','列名行位置','列名列位置','是否使用','需要细化','细化列名' 的信息
        """
        columns_detail_part_columns = ['列名', '列名行位置', '列名列位置', '是否使用', '需要细化', '细化列名']
        columns_info = pd.DataFrame(columns=columns_detail_part_columns)
        mylog.debug("start excel multi line hdr detect.")
        emlhd = ExcelMultiLineHdrDetect(file_path, sheet_name)
        row_start, col_start, row_end, col_end = emlhd.getColumnsPos(start_flag, end_flag)
        mylog.debug("pos:{},{},{},{}".format(row_start, col_start, row_end, col_end))
        modify_map = emlhd.getModifyMap(start_flag, end_flag)
        if not any(modify_map):
            mylog.critical(
                "检测到文件【{}】中的【{}】表头列区域无正常合并单位格，请确认是否需要处理！".format(file_path, sheet_name))
            raise HdrTypeError(
                "检测到文件【{}】中的【{}】表头列区域无正常合并单位格，请确认是否需要处理！".format(file_path, sheet_name))
        columns = emlhd.getColumns(start_flag, end_flag)
        # modify_data = emlhd.getModifyData(start_flag,end_flag)
        mylog.debug("modify map:{}".format(modify_map))
        # mylog.debug("columns:",columns)

        for col_index in range(columns.shape[1]):
            if modify_map[col_index]:
                for row_index, value in enumerate(columns[col_index + col_start].tolist()):
                    columns_info.loc[columns_info.shape[0], :] = [value, row_start + row_index, col_start + col_index,
                                                                  "是", "是", ""]
            else:
                columns_info.loc[columns_info.shape[0], :] = [columns[col_start + col_index].values[0], row_start,
                                                              col_start + col_index, "是", "否", ""]
        return columns_info

    def _walkUsedSheet(self):
        """
        根据使用表情况，遍历每个数据表，从中获取
        :return:
        """
        multi_line = self._used_sheets.loc[~self._used_sheets['单行列名'].isin(['是', 'Y', True, 'TRUE', 'True'])]
        self._multi_line_hdr_detect_list = []
        columns_detail_columns = ['文件编号', '文件路径','文件名称','Sheet表名','年度', '标记',  '列名起始标识', '列名终止标识',
                                  '列名', '列名行位置', '列名列位置', '是否使用', '需要细化', '细化列名']
        multi_line_conf_df = pd.DataFrame(columns=columns_detail_columns)
        if not multi_line.empty:
            # 根据标识获取表头结构
            for index, line in multi_line.iterrows():
                mylog.debug('分析文件{}多选头部结构'.format(line['Sheet表名']))
                file_id = line['文件编号']
                file_path = line['文件路径']
                file_name = line['文件名称']
                year = line['年度']
                flag = line['标记']
                sheet_name = line['Sheet表名']
                start_flag = line['列名起始标识']
                end_flag = line['列名终止标识']
                columns_same_part = [file_id, file_path, file_name,sheet_name,year, flag , start_flag, end_flag]
                mylog.debug("正在处理【{}】文件中的【{}】表的多行列名！".format(file_path, sheet_name))
                columns_info_df = self._findMultiLineInfo(file_path, sheet_name, start_flag, end_flag)
                for index_col, ever_col in columns_info_df.iterrows():
                    ever_line_data = columns_same_part + ever_col.tolist()
                    multi_line_conf_df.loc[multi_line_conf_df.shape[0], :] = ever_line_data
        return multi_line_conf_df

    def isNewDir(self):
        return self._new_dir